#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int count_field(const char *line);
char** get_field_arr(const char *line);

struct student {
	int id;
	char *name;
	double point;
};

void print_student_info(struct student *stu);

int main() {
	const char *line = "  \"4\",def,\"4.4\"  \0";

	int count = count_field(line);
	char **result = get_field_arr(line);
	printf("--- Parse line result ---\n");
	for (int i = 0; i < count; i++) {
		printf("result[%d] = %s\n", i, result[i]);
	}

	struct student stu;
	stu.id = atoi(result[0]);
	stu.name = strdup(result[1]);
	stu.point = atof(result[2]);
	print_student_info(&stu);

	return 0;
}

int count_field(const char *line) {
	const char *p_line = line;
	int count = 1, is_quoted = 0;

	for (; *p_line != '\0'; p_line++) {
		if (is_quoted) {
			if (*p_line == '\"') {
				if (p_line[1] == '\"') {
					p_line++;
					continue;
				}
				is_quoted = 0;
			}
			continue;
		}

		switch (*p_line) {
			case '\"':
				is_quoted = 1;
				continue;
			case ',':
				count++;
				continue;
			default:
				continue;
		}
	}

	if (is_quoted) {
		return -1;
	}

	return count;
}

char** get_field_arr(const char *line) {
	int count = count_field(line);
	if (count == -1) {
		return NULL;
	}

	char **buf = malloc(sizeof(char*) * (count + 1));
	if (buf == NULL) {
		return NULL;
	}
	char **pbuf = buf;

	char *tmp = malloc(strlen(line) + 1);
	if (tmp == NULL) {
		free(buf);
		return NULL;
	}
	*tmp = '\0';
	char *ptmp = tmp;

	const char *p_line = line;
	int is_quoted = 0, is_end = 0;

	for (; ; p_line++) {
		if (is_quoted) {
			if (*p_line == '\0') {
				break;
			}

			if (*p_line == '\"') {
				if (p_line[1] == '\"') {
					*ptmp++ = '\"';
					p_line++;
					continue;
				}
				is_quoted = 0;
			} else {
				*ptmp++ = *p_line;
			}

			continue;
		}

		switch (*p_line) {
			case '\"':
				is_quoted = 1;
				continue;
			case '\0':
				is_end = 1;
			case ',':
				*ptmp = '\0';
				*pbuf = strdup(tmp);

				if (*pbuf == NULL) {
					for (pbuf--; pbuf >= buf; pbuf--) {
						free(*pbuf);
					}
					free(buf);
					free(tmp);
					return NULL;
				}

				pbuf++;
				ptmp = tmp;

				if (is_end) {
					break;
				} else {
					continue;
				}

			default:
				*ptmp++ = *p_line;
				continue;
		}

		if (is_end) {
			break;
		}
	}

	*pbuf = NULL;
	free(tmp);
	return buf;
}

void print_student_info(struct student *stu) {
	printf("--- Student info ---\n");
	printf("%d\t%s\t%f\n", stu->id, stu->name, stu->point);
}
